REM *****************************************************
REM --------------------- SciNoto --------------------- *
REM Позволяет связать текстовый редактор OOo Writer     *
REM и пакет прикладных математических программ SciLab.  *
REM                                                     *
REM Copyright(c) 2010, Василий Почкаенко                *
REM                    PochkaenkoV@yandex.ru            *
REM                                                     *
REM Замечания, пожелания и вопросы пишите мне на        *
REM электронный ящик с пометкой в теме: SciNoto         *
REM                                                     *
REM******************************************************
REM Описание модуля:                                    |
REM Основной модуль программы                           |
REM------------------------------------------------------


Option Explicit

REM Множество всех полей ввода данных
Global AroRegionojEnigado() as object
Global Numero(0 to 0) as integer

REM Размер множества
Global KvantoRegionojEnigado as integer

REM Флаг создания множества
Global BaskuloKreajxo as Boolean

REM Создание множества из существующих полей
Sub KreajxoAro
  dim Regionoj
  dim Regiono
  dim i as integer
  dim j as integer
  dim n as integer
  KvantoRegionojEnigado = 0
  Regionoj = ThisComponent.getTextFields().createEnumeration()
  Numero(0) = 0
  REM Перебор всех полей
  While (Regionoj.hasMoreElements())
    Regiono = Regionoj.nextElement()
    If (Regiono.supportsService("com.sun.star.text.TextField.Input")) Then
      If(left(Regiono.Hint, 29) = "Данные для обработки в SciLab") Then
      	j = KvantoRegionojEnigado REM KvantoRegionojEnigado - 1, чтоб лышнюю оперецию не делать, просваюваю j до увеличения KvantoRegionojEnigado
      	i = i + 1
      	KvantoRegionojEnigado = i
      	ReDim preserve AroRegionojEnigado(1 To i) As object
      	ReDim preserve Numero(0 To i) As integer
      	n = Val(Mid(Regiono.Hint, 32))
'      	print n
      	While(j >= 0)
      		if n < Numero(j) then
'      			print n & "<" & Numero(j)
      			Numero(j+1) = Numero(j)
      			AroRegionojEnigado(j+1) = AroRegionojEnigado(j)
      		else
'      			print n & ">" & Numero(j)
      			Numero(j+1) = n
      			AroRegionojEnigado(j+1) = Regiono
      			j = 0 REM Чтобы выйти из цикла
      		end if
      		j = j - 1
      	Wend
      End if
    End if
  Wend
  BaskuloKreajxo = true
End Sub

REM Подсчитать кол-во полей
sub KalkuliKvantoRegionojEnigado
  dim Regionoj
  dim Regiono
  KvantoRegionojEnigado = 0
  Regionoj = ThisComponent.getTextFields().createEnumeration()
  Numero(0) = 0
  REM Перебор всех полей
  While (Regionoj.hasMoreElements())
    Regiono = Regionoj.nextElement()
    If (Regiono.supportsService("com.sun.star.text.TextField.Input")) Then
      If(left(Regiono.Hint, 29) = "Данные для обработки в SciLab") Then
      	KvantoRegionojEnigado = KvantoRegionojEnigado + 1
      End if
    End if
  Wend
end sub

REM Подсчитать макс номер поля
function KalkuliMaksimumaNumeroRegionoEnigado as integer
  dim rez as integer
  rez = 0
  dim buff as integer
  dim Regionoj
  dim Regiono
  KvantoRegionojEnigado = 0
  Regionoj = ThisComponent.getTextFields().createEnumeration()
  Numero(0) = 0
  REM Перебор всех полей
  While (Regionoj.hasMoreElements())
    Regiono = Regionoj.nextElement()
    If (Regiono.supportsService("com.sun.star.text.TextField.Input")) Then
      If(left(Regiono.Hint, 29) = "Данные для обработки в SciLab") Then
        buff = Mid(Regiono.Hint, 32)
      	if buff > rez then
      	  rez = buff
      	end if
      End if
    End if
  Wend
'  print rez
  KalkuliMaksimumaNumeroRegionoEnigado = rez
end function

REM Процедура для добавления нового поля ввода
Sub InsertiRegionoEnigado
  dim Areo REM Одно выделение
  dim Areoj REM Все выделения в документе
' dim Kursoro REM Текстовый курсор
  dim oRegionoEnigado REM Обьект поля ввода
  dim MaksimumaNumeroRegionoEnigado as integer
  REM Получаю все выделения в текущем документе
  Areoj = StarDesktop.CurrentComponent.getCurrentSelection()
  REM Если текущий контроллер отсутствует, возвращается NULL.
  If IsNull(Areoj) Then
    Exit Sub
  Else if Areoj.getCount() = 0 Then
      REM Выделений нет
      print "Выделите одну область"
    else if Areoj.getCount() > 1 Then
        print "Выделите только одну область"
      else
        REM Выделена только одна область
        REM Получаю первое и единственное выделение
        Areo = Areoj.getByIndex(0)
        REM Есть только одно выделение. Может быть пустым

        REM Вычисля ю ваксимальный номер поля ввода и увеличиваю его на 1, что бы создать новое поле
        MaksimumaNumeroRegionoEnigado = KalkuliMaksimumaNumeroRegionoEnigado + 1
        REM Создаю текстовое поле ввода, содержащее выделенный текст
        oRegionoEnigado = ThisComponent.createInstance("com.sun.star.text.TextField.Input")
'        KvantoRegionojEnigado = KvantoRegionojEnigado + 1
        oRegionoEnigado.Hint = "Данные для обработки в SciLab №" & MaksimumaNumeroRegionoEnigado
        oRegionoEnigado.Content = Areo.getString()
        ThisComponent.Text.insertTextContent(Areo, oRegionoEnigado, True)

        REM Создаю текстовое поле для вывода результатов обработки данных в SciLab
        oRegionoEnigado = ThisComponent.createInstance("com.sun.star.text.TextField.Input")
        oRegionoEnigado.Hint = "Результат обработки данных в SciLab №" &  MaksimumaNumeroRegionoEnigado
        ThisComponent.Text.insertTextContent(Areo.getEnd(), oRegionoEnigado,false)

        ThisComponent.getText().insertString(Areo.getEnd(), CHR(10), false)
      end if
    end if
  end if
End sub

REM Процедура для удаления выделенного поля ввода с сохранением текста
Sub EksciziRegionoEnigato
  dim Areo as Object REM Одно выделение
  dim Areoj as Object REM Все выделения в документе
  Areoj = StarDesktop.CurrentComponent.getCurrentSelection()
  If IsNull(Areoj) Then
    Exit Sub
  Else if Areoj.getCount() = 0 Then
      REM Выделений нет
      print "Выделите одну область"
    else
      dim oTeksto as Object rem Текст открытого документа
      oTeksto = ThisComponent.getText()
      dim KursoroLiva as Object rem Курсор указывающий на левую границу выделенного текста
      dim KursoroPrava as Object rem Курсор указывающий на правую границу выделенного текста
      dim s as string
      dim NumeroRegionoEnigato as integer rem Номер удаляемогополя ввода
      dim Regionoj rem Множество полей
      dim Regiono rem Одно поле


      rem Перебираю все выделенные области
      dim i as integer
      for i = 0 to (Areoj.getCount() - 1)
        Areo = Areoj.getByIndex(i)
        KursoroLiva = ProviziLivaKursoro(Areo, oTeksto)
        KursoroPrava = ProviziPravaKursoro(Areo, oTeksto)

        rem Перебираю по 1 символу, пока они есть, и пока левый курсор действительно слева
        do
          rem Если курсор указывает на текстовое поле
          If not IsEmpty(KursoroLiva.TextField) Then
            rem Если оно является полем ввода
            rem и его заголовок содержит "Данные для обработки в SciLab №"
             if KursoroLiva.TextField.supportsService("com.sun.star.text.TextField.Input") and left(KursoroLiva.textField.Hint, 31)="Данные для обработки в SciLab №" then
              rem Нашлось поле ввода данных для SciLab

              rem Заменю поле на текст содержащийся в нём
              s = KursoroLiva.textField.Content
              NumeroRegionoEnigato = Mid(KursoroLiva.textField.Hint, 32)
              KursoroLiva.goRight(1, true)
              KursoroLiva.setString(s)

              REM Ищу поля результатов
              Regionoj = ThisComponent.getTextFields().createEnumeration()
              While (Regionoj.hasMoreElements())
                Regiono = Regionoj.nextElement()
                rem Если текстовое поле является полем ввода
                If (Regiono.supportsService("com.sun.star.text.TextField.Input")) Then
                  If(Regiono.Hint = "Результат обработки данных в SciLab №" & NumeroRegionoEnigato) Then
                    Regiono.getAnchor().setString("")
                  End if
                End If
              wend
            end if
          end if
        loop while (KursoroLiva.goRight(1, false) and oTeksto.compareRegionStarts(KursoroLiva, KursoroPrava) > 0)
      next
    end if
  end if
End sub


REM Процедура вычисления всех областей ввода
sub KomputiCXiujRegionojEnigadoj
  REM Создаю упорядоченное множество полей
  KreajxoAro

  REM Выполняю её только, если есть поля ввода
  If(KvantoRegionojEnigado > 0) then
  	rem Проверяю, есть ли необходимые для работы файлы. Если нет создаю
  	AnticipaKontrolo

    dim Regionoj
    dim Regiono
    dim Regionoj2
    dim Regiono2
    dim s as string
    dim s2 as string
    dim n as integer
    dim i as integer
    dim j as integer
    Regionoj = ThisComponent.getTextFields().createEnumeration()
    REM Открываю файл для записи скрипта передоваемого в SciLab
    dim f
    f = FreeFile()
    Open ProviziDatumoDosierujo() & GetPathSeparator() & "tmp.sce" For Output as #f
    REM Перебираю все текстовые поля и записываю их в скрипт
    for i = 1 to KvantoRegionojEnigado
        s = AroRegionojEnigado(i).Hint
          s2 = AroRegionojEnigado(i).Content
          n = InStr(s2, "plot")
          j = 0
          while n
          	if InStr(n, s2, CHR(10)) then
          	  s2 = mid(s2, 1, (InStr(n, s2, CHR(10))-n)) & "xs2bmp(0, '" & ProviziDatumoDosierujo() & GetPathSeparator() & ".scinoto" &  GetPathSeparator() & Mid(s, 32) & "_" & j & ".bmp')" & mid(s2, (InStr(n, s2, CHR(10)-n)))
          	else
	          s2 = s2 & CHR(10) & "xs2bmp(0, '" & ProviziDatumoDosierujo() & GetPathSeparator() & ".scinoto" &  GetPathSeparator() & Mid(s, 32) & "_" & j & ".bmp')"
          	end if
          	n = InStr(n + 4, s2, "plot")
          wend
          print #f s2
          print #f "MarkoFinoRegionoEnigado = " & Mid(s, 32) & ";" REM Метка разделяющая поля ввода
    Next
    close #f

    REM Выполняю скрипт в SciLab
    shell(ProviziOperacioLancxooSciLab(), 1, "-f " & Chr$(34) & ProviziDatumoDosierujo() &  GetPathSeparator() & "shell_scilab" & Chr$(34), true)

    dim Respondoj(1 to 1) as string REM Массив строк, содержащий ответ SciLab
    dim Ind(1 to 1) as integer REM Массив индексов для ответов SciLab

    REM Открываю вайл с ответом SciLab и читаю его в массив для ответа
    Open ProviziDatumoDosierujo() & GetPathSeparator() & "output" For input as #f
    i = 1
    Do Until EOF(#f)
      line input #f, s
      if (InStr(s, "MarkoFinoRegionoEnigado")) then
        REM Строка содержит метку конца области

        REM Запоминаю индекс области
        Ind(i) = Val(Mid(s, 29, Len(s) - 27))

        REM Увеличиваю массивы
        i = i + 1
        ReDim Preserve Ind(1 to i) as integer
        ReDim Preserve Respondoj(1 to i) as string
      else
        if (InStr(s, "-->")) Then
        else
          REM Строка не является ни меткой, ни командой

          Respondoj(i) = Respondoj(i) & s & CHR(10)
        end if
      end if
    loop

    REM Перебираю все текстовые поля и заполняю поля результатов
    Regionoj = ThisComponent.getTextFields().createEnumeration()
    While (Regionoj.hasMoreElements())
      Regiono = Regionoj.nextElement()
      If (Regiono.supportsService("com.sun.star.text.TextField.Input")) Then
        s = Regiono.Hint
        If(left(s, 35) = "Результат обработки данных в SciLab") Then
          For j = 1 to i-1
            If Ind(j) = Mid(s, 38) Then
'              Print j
              Regiono.Content = Respondoj(j)
              ThisComponent.getText().insertString(Regiono.getAnchor().getEnd(), " ", false) REM Заставляю перерисовать строоку
            end if
          Next
        End if
      End if
    Wend

    rem Перебираю все поля ввода данных SciLab и ищу для них картинки, если есть вставляю
rem    dim oGraphicObject as Object
rem    for i = 1 to UBound(Numero)
rem      s = dir("~" &  GetPathSeparator() & ".scinoto" &  GetPathSeparator() & Numero(i) & "*.bmp")
rem      while (s <> "")
rem      	oGraphicObject = ThisComponent.createInstance("com.sun.star.text.GraphicObject")
rem        oGraphicObject.GraphicURL = "file://~/.scinoto/" & s
rem        oGraphicObject.AnchorType = 1
rem        ThisComponent.GetText().insertTextContent(AroRegionojEnigado(i).getAnchor().getEnd(), oGraphicObject, false)
rem        s = dir()
rem      wend
rem    next
  else
    print "Создайте поля ввода"
  end if
end sub

rem oSel - выделение текста или диапазон курсора
rem oText - текстовый объект
Function ProviziLivaKursoro(oSel, oText)
  Dim oRange
  Dim oCursor
  If oText.compareRegionStarts(oSel.getEnd(), oSel) >= 0 Then
    oRange = oSel.getEnd()
  Else
    oRange = oSel.getStart()
  End If
  oCursor = oText.CreateTextCursorByRange(oRange)
  oCursor.goRight(0, False)
  ProviziLivaKursoro = oCursor
End Function

rem oSel - выделение текста или диапазон курсора
rem oText - текстовый объект
Function ProviziPravaKursoro(oSel, oText)
  Dim oRange
  Dim oCursor
  If oText.compareRegionStarts(oSel.getEnd(), oSel) >= 0 Then
    oRange = oSel.getStart()
  Else
    oRange = oSel.getEnd()
  End If
  oCursor = oText.CreateTextCursorByRange(oRange)
  oCursor.goLeft(0, False)
  ProviziPravaKursoro = oCursor
End Function

rem Создать файл начального скрипта передаваемого при запуске SciLab
Sub krei__shell_scilab
rem  dim s
rem  s = "diary('" & ProviziDatumoDosierujo() &  GetPathSeparator() & "output');" & CHR(10) & "exec('" & ProviziDatumoDosierujo() &  GetPathSeparator() & "tmp.sce')" & CHR(10) & "exit"  & CHR(10)
rem  UniWrite(s, ProviziDatumoDosierujo() &  GetPathSeparator() & "shell_scilab") 
  REM Открываю файл для записи
  dim f
  f = FreeFile()
  Open ProviziDatumoDosierujo() &  GetPathSeparator() & "shell_scilab" For Output as #f
    print #f "diary('" & ProviziDatumoDosierujo() &  GetPathSeparator() & "output');" & CHR(10) & "exec('" & ProviziDatumoDosierujo() &  GetPathSeparator() & "tmp.sce')" & CHR(10) & "exit"  & CHR(10)

  close #f
End sub

rem Создать пустой файл возврата из SciLab
Sub krei__output
  REM Открываю файл для записи
  dim f
  f = FreeFile()
  Open ProviziDatumoDosierujo() & GetPathSeparator() & "output" For Output as #f
    print #f ""

  close #f
End sub

rem Возвращает путь к домашнему каталогу пользователя
Function ProviziDatumoDosierujo()
  If (GetGuiType() = 4) then
    rem ОС - Linux
    ProviziDatumoDosierujo = Environ("HOME") & GetPathSeparator() & ".scinoto" 
  else
    if (GetGuiType() = 1) then
      rem OC - Windows
      ProviziDatumoDosierujo = Environ("HOMEDRIVE") & Environ("HOMEPATH") & GetPathSeparator() & "Application Data" & GetPathSeparator() & "SciNoto" 
    end if
  end if
End Function

rem Возвращает команду запуска SciLab
Function ProviziOperacioLancxooSciLab()
  If (GetGuiType() = 4) then
    rem ОС - Linux
    ProviziOperacioLancxooSciLab = "scilab"
  else
    if (GetGuiType() = 1) then
      rem OC - Windows
      
      rem Имя файла где ллележит команда запуска SciLab
      dim OperacioLancxooSciLab
      OperacioLancxooSciLab = ProviziDatumoDosierujo() &  GetPathSeparator() & "OperacioLancxooSciLab"

      dim f
      f = FreeFile()
      dim rez
      if (dir(OperacioLancxooSciLab) = "") then
        rem Если нет файла с команой запуска, то спрошу команду у пользователя, зепишу её
        rem в файл и передам как результат функции
      	Open OperacioLancxooSciLab For Output as #f
      	rez = DemandiOperacioLancxooSciLab()
      	print #f rez
      	ProviziOperacioLancxooSciLab = rez
      else
        rem  Если есть файл, то прочитаю команду из него.
      	Open OperacioLancxooSciLab For Input as #f
        line input #f, rez
        ProviziOperacioLancxooSciLab = rez
      end if
      close #f
    end if
  end if
End Function

rem Спрашиает команду запуска SciLab у пользователя
Function DemandiOperacioLancxooSciLab()
  Dim oLib
  Dim oLibDlg
  Dim oProviziOperacioLancxooSciLabDlg
  'Библиотека, которая содержит диалог
  'Диалог, сохраненный в библиотеке
  REM Сначала, загрузим библиотеку.
  REM Если диалог сохранен в библиотеке прикладного уровня, а не в документе
  REM то должен использоваться GlobalScope.DialogLibraries.
  GlobalScope.DialogLibraries.loadLibrary("SciNoto")
  REM Получим всю библиотеку, когда она будет загружена.
  oLib = DialogLibraries.getByName("SciNoto")
  REM Получите диалог, сохраненный в библиотеке.
  REM Я обычно думаю об этом, как об определении диалога.
  oLibDlg = oLib.getByName("proviziOperacioLancxooSciLabDlg")
  REM Создадим диалог, который может использоваться.
  oProviziOperacioLancxooSciLabDlg = CreateUnoDialog(oLibDlg)

  REM Теперь запустим диалог.
  REM Метод execute() - действительно функция, которая возвращает 1, если
  REM используется OK для закрытия диалога и 0, если используется Cancel для
  REM закрытия диалога. Нажатие кнопки Close в верхнем правом углу диалога
  REM считается равнозначным нажатию Cancel.
  if (oProviziOperacioLancxooSciLabDlg.execute()=0) then
    Stop
  end if
  DemandiOperacioLancxooSciLab = oProviziOperacioLancxooSciLabDlg.getControl("SciLabFileName").getText()
End Function

rem Проверяю, есть ли необходимые для работы файлы. Если нет создаю
Sub AnticipaKontrolo
  if dir(ProviziDatumoDosierujo() &  GetPathSeparator() & "shell_scilab") = "" then
    rem Создать файл начального скрипта передоваемого при запуске SciLab
    krei__shell_scilab
    rem Создать пустой файл возврата из SciLab
    krei__output
  end if
end sub

